package services

import (
	"fmt"
	"gitee.com/captials-team/ubdframe/src/common/utils"
	"gitee.com/captials-team/ubdframe/src/domain/converts"
	"gitee.com/captials-team/ubdframe/src/domain/dto"
	"gitee.com/captials-team/ubdframe/src/domain/dto/paginate"
	"gitee.com/captials-team/ubdframe/src/domain/dto/respdata"
	"gitee.com/captials-team/ubdframe/src/domain/interfaces"
	"gitee.com/captials-team/ubdframe/src/domain/models"
	"gitee.com/captials-team/ubdframe/src/infrastructure/caches"
	v1log "gitee.com/captials-team/ubdframe/src/pkg/logs"
	"go.uber.org/dig"
	"gorm.io/gorm"
)

type OrganizeService struct {
	l           v1log.ILog
	organizeDao interfaces.ItfOrganize
	relateDao   interfaces.ItfOrganizeRelate

	cacheById *caches.CacheFacade[int64, *models.Organize]
}

func NewOrganizeService(di *dig.Container, l v1log.ILog, organizeDao interfaces.ItfOrganize, relateDao interfaces.ItfOrganizeRelate, cache caches.ItfCache) *OrganizeService {
	svc := &OrganizeService{
		l:           l,
		organizeDao: organizeDao,
		relateDao:   relateDao,
		cacheById:   caches.NewCacheFacade[int64, *models.Organize](cache),
	}

	svc.cacheById.WithValueFunc(svc.orgCacheValue).WithKeyPrefix("org_")

	return svc
}

// orgCacheValue 缓存org值获取方法
func (s *OrganizeService) orgCacheValue(id int64) *models.Organize {
	find, err := s.organizeDao.Query(id)
	if err != nil {
		s.l.Error("query organize-%d fail %s", id, err)
		return nil
	}
	s.l.Info("org=%d %+v", id, s)
	return find
}

func (s *OrganizeService) Search(search dto.SearchOrganizeParams, pa *paginate.Pager) ([]*respdata.OrganizeListItem, *paginate.Pager, error) {
	scope := func(db *gorm.DB) *gorm.DB {
		if search.Keywords != "" {
			keywords := "%" + search.Keywords + "%"
			db = db.Where("(name like ?) ", keywords)
		}
		if search.OrgType != "" {
			db = db.Where("type=? ", search.OrgType)
		}
		if search.Status > 0 {
			db = db.Where("status=?", search.Status)
		}

		if search.PType == 1 {
			//只查一级
			db = db.Where("pid=?", search.Pid)
		}
		if search.PType == 0 && search.Pid > 0 {
			db = db.Where(fmt.Sprintf("id in (%s)", s.relateDao.SqlForSearchChild(search.Pid, 0)))
		}
		if search.IsSimple {
			db = db.Select("id", "name", "type", "pid", "status")
		}
		db = db.Order("id desc").Omit("description")
		return db
	}

	var list []*models.Organize
	var err error
	if search.IsAll {
		list, err = s.organizeDao.All(scope)
		pa = &paginate.Pager{
			Page:  1,
			Size:  len(list),
			Total: int64(len(list)),
		}
	} else {
		list, pa, err = s.organizeDao.Search(pa, scope)
	}
	if err != nil {
		return nil, nil, err
	}

	var returnList []*respdata.OrganizeListItem
	for _, v := range list {
		returnList = append(returnList, s.convertListItem(v))
	}

	return returnList, pa, nil
}

func (s *OrganizeService) convertListItem(org *models.Organize) *respdata.OrganizeListItem {
	d := utils.CopyTo(org, new(respdata.OrganizeListItem))
	if org.Pid > 0 {
		parent, _ := s.cacheById.GetOrLoad(org.Pid)
		if parent == nil {
			s.l.Error("parent=%d not exists", org.Pid)
			return nil
		}
		d.ParentName = parent.Name
	}
	return d
}

func (s *OrganizeService) Tree(search dto.TreeOrganizeParams) ([]*dto.TreeNode[*models.Organize], error) {
	scope := func(db *gorm.DB) *gorm.DB {
		if search.OrgType != "" {
			db = db.Where("type=? ", search.OrgType)
		}

		if search.PType == 1 {
			//只查一级
			db = db.Where("pid=?", search.Pid)
		}
		if search.PType == 0 && search.Pid > 0 {
			db = db.Where(fmt.Sprintf("id in (%s)", s.relateDao.SqlForSearchChild(search.Pid, 0)))
		}

		db = db.Select("id", "name", "type", "pid")
		db = db.Order("id desc").Omit("description")
		return db
	}

	list, err := s.organizeDao.All(scope)
	if err != nil {
		return nil, err
	}
	//s.l.Debug("LIST= %+v", list)

	if search.Pid > 0 {
		return converts.ConvertTree(list, fmt.Sprintf("%d", search.Pid)), nil
	}

	return converts.ConvertTree(list), nil
}

func (s *OrganizeService) Query(id int64) (*respdata.OrganizeDetail, error) {
	org, err := s.organizeDao.Query(id)
	if err != nil {
		return nil, err
	}
	if org == nil {
		return nil, nil
	}
	d := utils.CopyTo(org, new(respdata.OrganizeDetail))
	if org.Pid > 0 {
		parent, _ := s.cacheById.GetOrLoad(org.Pid)
		if parent == nil {
			return nil, fmt.Errorf("parent=%d not exists", org.Pid)
		}
		d.ParentName = parent.Name
	}

	return d, nil
}

func (s *OrganizeService) Add(add models.Organize) (int64, error) {
	orgId, err := s.organizeDao.Add(add)
	if err != nil {
		return 0, err
	}

	_, err = s.fixParentRelation(orgId, add.Pid)
	if err != nil {
		return 0, err
	}
	//缓存删除
	if err := s.cacheById.Delete(orgId); err != nil {
		return orgId, err
	}

	return orgId, nil
}

func (s *OrganizeService) Update(id int64, up models.Organize) (int64, error) {
	affect, err := s.organizeDao.Update(id, up)
	if err != nil {
		return 0, err
	}
	_, err = s.fixParentRelation(id, up.Pid)
	if err != nil {
		return 0, err
	}
	//缓存删除
	if err := s.cacheById.Delete(id); err != nil {
		return affect, err
	}

	return affect, nil
}

func (s *OrganizeService) Delete(id int64) (int64, error) {
	//删除子组织
	affect1, err := s.DeleteAllChild(id)
	if err != nil {
		return affect1, err
	}
	affect2, err := s.deleteOne(id)
	if err != nil {
		return affect1 + affect2, err
	}

	return affect1 + affect2, nil
}

// DeleteAllChild 删除下级
func (s *OrganizeService) DeleteAllChild(pid int64) (int64, error) {
	list, err := s.relateDao.All(func(db *gorm.DB) *gorm.DB {
		return db.Where("org_parent", pid)
	})
	if err != nil {
		return 0, err
	}
	var ids []int64
	utils.LookupArray(list, func(m *models.OrganizeRelate, i int) {
		ids = append(ids, m.OrgId)
	})
	for _, id := range ids {
		_, err := s.deleteOne(id)
		if err != nil {
			return 0, err
		}
	}

	return int64(len(ids)), nil
}

// DeleteAllChild 删除下级
func (s *OrganizeService) deleteOne(id int64) (int64, error) {
	affect, err := s.organizeDao.Delete(id)

	_, err = s.relateDao.DeleteByScope(func(db *gorm.DB) *gorm.DB {
		return db.Where("org_id", id)
	})
	if err != nil {
		return 0, err
	}
	//缓存删除
	if err := s.cacheById.Delete(id); err != nil {
		return affect, err
	}
	return affect, nil
}

func (s *OrganizeService) fixParentRelation(orgId int64, parentId int64) (int64, error) {
	//先删除原来的关系
	_, err := s.relateDao.DeleteByScope(func(db *gorm.DB) *gorm.DB {
		return db.Where("org_id", orgId)
	})
	if err != nil {
		return 0, err
	}

	//查询新上级的关系
	list, err := s.relateDao.SearchParent(parentId, 0)
	if err != nil {
		return 0, err
	}

	var newRelate []models.OrganizeRelate
	for _, v := range list {
		newRelate = append(newRelate, models.OrganizeRelate{
			OrgId:     orgId,
			OrgParent: v.OrgParent,
			Level:     v.Level + 1,
		})
	}

	newRelate = append(newRelate, models.OrganizeRelate{
		OrgId:     orgId,
		OrgParent: parentId,
		Level:     1,
	})

	for _, v := range newRelate {
		_, err := s.relateDao.Add(v)
		if err != nil {
			return 0, err
		}
	}

	return int64(len(list)), nil
}

func (s *OrganizeService) Enable(id int64, status int) (int64, error) {
	defer s.cacheById.Delete(id)
	return s.organizeDao.ResetStatus(id, status)
}
